﻿using System;
using System.Collections.Generic;
using System.Linq;
using ReagentStore.BLL;
using ReagentStore.ERM;
using ReagentStore.Resources.Properties;

namespace ReagentStore.PRT
{
	public class Presentation
	{
		#region Singleton

		private static readonly Presentation Instance = new Presentation();

		private Presentation()
		{
		}

		public static Presentation CreateInstance()
		{
			return Instance;
		}

		#endregion

		#region Event declaration

		public EntityEventProxy CatalogEventProxy = new EntityEventProxy();
		public EntityEventProxy MessageProxy = new EntityEventProxy();
		public EntityEventProxy ProductEventProxy = new EntityEventProxy();
		public EntityEventProxy ReagentEventProxy = new EntityEventProxy();
		public EntityEventProxy RecordEventProxy = new EntityEventProxy();

		public void RaiseEventWhenCatalogsUpdated()
		{
			IList<Catalog> catalogs = new CatalogBLL().DALAccessor.GetEntities();

			// rebuild the treeview of catalogs.
			CatalogEventProxy.RaiseEvent(this, new EntityEventArgs(catalogs));
			RaiseEventWhenReagentsUpdated(new ReagentBLL().DALAccessor.GetEntities());
		}

		private void RaiseEventWhenReagentsUpdated(IList<Reagent> reagents)
		{
			ReagentEventProxy.RaiseEvent(this, new EntityEventArgs(reagents));
			RaiseEventWhenProductsUpdated(null);
		}

		private void RaiseEventWhenProductsUpdated(IList<Product> products)
		{
			RaiseEventWhenRecordsUpdated(null);

			if (products == null)
			{
				ProductEventProxy.RaiseEvent(this, new EntityEventArgs(null));
				return;
			}

			ProductEventProxy.RaiseEvent(this, products.Count == 0 ? new EntityEventArgs(null) : new EntityEventArgs(products));
		}

		private void RaiseEventWhenRecordsUpdated(IList<Record> records)
		{
			if (records == null)
			{
				RecordEventProxy.RaiseEvent(this, new EntityEventArgs(null));
				return;
			}

			RecordEventProxy.RaiseEvent(this, records.Count == 0 ? new EntityEventArgs(null) : new EntityEventArgs(records));
		}

		public void RaiseEventWhenCurrentReagentChanged(Reagent reagent)
		{
			if (reagent == null)
			{
				ReagentEventProxy.RaiseEvent(this, new EntityEventArgs(null));
				RaiseEventWhenProductsUpdated(null);
				return;
			}

			ReagentEventProxy.RaiseEvent(this, new EntityEventArgs(reagent));

			List<Product> products =
				new ProductBLL().DALAccessor.GetEntitiesByReagentId(reagent.ReagentID).OrderBy(p => p.ExpirationDate).ToList();
			RaiseEventWhenProductsUpdated(products);

			List<Record> records =
				new RecordBLL().DALAccessor.GetEntitiesByReagentId(reagent.ReagentID).OrderBy(r => r.Date).ToList();
			RaiseEventWhenRecordsUpdated(records);
		}


		public void RaiseEventWhenCurrentProductChanged(Product product)
		{
			if (product == null)
			{
				RaiseEventWhenRecordsUpdated(null);
				return;
			}

			List<Record> records =
				new RecordBLL().DALAccessor.GetEntitiesByProductId(product.ProductID).OrderBy(r => r.Date).ToList();
			RaiseEventWhenRecordsUpdated(records);
		}

		private void RaiseMessage(string message)
		{
			MessageProxy.RaiseEvent(this, new EntityEventArgs(message));
		}

		#endregion

		#region CUD operation

		private readonly CatalogBLL _bllCatalog = new CatalogBLL();
		private readonly ProductBLL _bllProduct = new ProductBLL();
		private readonly ReagentBLL _bllReagent = new ReagentBLL();
		private readonly RecordBLL _bllRecord = new RecordBLL();

		public void Initialize()
		{
			RaiseEventWhenCatalogsUpdated();
		}

		public void InsertCatalog(Catalog catalog)
		{
			try
			{
				_bllCatalog.Insert(catalog);
				RaiseEventWhenCatalogsUpdated();
			}
			catch (ApplicationException e)
			{
				RaiseMessage(e.Message);
			}
		}

		public void UpdateCatalog(Catalog catalog)
		{
			try
			{
				_bllCatalog.Update(catalog);
				RaiseEventWhenCatalogsUpdated();
			}
			catch (ApplicationException e)
			{
				RaiseMessage(e.Message);
			}
		}

		public void DeleteCatalog(Catalog catalog)
		{
			try
			{
				_bllCatalog.Delete(catalog);
				RaiseEventWhenCatalogsUpdated();
			}
			catch (ApplicationException e)
			{
				RaiseMessage(e.Message);
			}
		}

		public void InsertReagent(Reagent reagent)
		{
			try
			{
				_bllReagent.Insert(reagent);
				RaiseEventWhenReagentsUpdated(_bllReagent.DALAccessor.GetEntities());
			}
			catch (ApplicationException e)
			{
				RaiseMessage(e.Message);
			}
		}

		public void UpdateReagent(Reagent reagent)
		{
			try
			{
				_bllReagent.Update(reagent);
				RaiseEventWhenReagentsUpdated(_bllReagent.DALAccessor.GetEntities());
			}
			catch (ApplicationException e)
			{
				RaiseMessage(e.Message);
			}
		}

		public void DeleteReagent(Reagent reagent)
		{
			try
			{
				_bllReagent.Delete(reagent);
				RaiseEventWhenReagentsUpdated(_bllReagent.DALAccessor.GetEntities());
			}
			catch (ApplicationException e)
			{
				RaiseMessage(e.Message);
			}
		}

		public void InsertProduct(Product product)
		{
			try
			{
				_bllProduct.Insert(product);
				RaiseMessage(DefaultResources.OPERATION_SUCCESS);
				RaiseEventWhenCatalogsUpdated();
			}
			catch (ApplicationException e)
			{
				RaiseMessage(e.Message);
			}
		}

		public void UpdateProduct(Product product)
		{
			try
			{
				_bllProduct.Update(product);
				RaiseMessage(DefaultResources.OPERATION_SUCCESS);
				RaiseEventWhenCatalogsUpdated();
			}
			catch (ApplicationException e)
			{
				RaiseMessage(e.Message);
			}
		}

		public void DeleteProduct(Product product)
		{
			try
			{
				_bllProduct.Delete(product);
				RaiseMessage(DefaultResources.OPERATION_SUCCESS);
				RaiseEventWhenCatalogsUpdated();
			}
			catch (ApplicationException e)
			{
				RaiseMessage(e.Message);
			}
		}

		public void InsertRecord(Record record)
		{
			try
			{
				_bllRecord.Insert(record);
				RaiseMessage(DefaultResources.OPERATION_SUCCESS);
				RaiseEventWhenCatalogsUpdated();
			}
			catch (ApplicationException e)
			{
				RaiseMessage(e.Message);
			}
		}

		public void DeleteRecord(Record record)
		{
			try
			{
				Product product = _bllProduct.DALAccessor.GetEntityById(record.ProductID);
				Reagent reagent = _bllReagent.DALAccessor.GetEntityById(product.ReagentID);
				_bllRecord.Delete(record);
				RaiseEventWhenCurrentReagentChanged(reagent);
			}
			catch (ApplicationException e)
			{
				RaiseMessage(e.Message);
			}
		}

		#endregion
	}
}